<template>
  <div>
    <n-card style="margin-bottom: 5px;height: 120px;">
      <n-spin :show="resourceLoading">
        <n-alert title="Fooocus无法访问" type="error" v-if="!isResourceOk">
          远程资源无法访问,请确认资源是否正常!!!
        </n-alert>
        <n-form v-else inline :model="text2ImgPrompt" ref="formRef1" :rules="rules">
          <n-grid :x-gap="10">
            <n-grid-item span="6">
              <n-form-item label="CHECKPOINT" path="base_model_name">
                <n-select
                    v-model:value="text2ImgPrompt.base_model_name"
                    :options="modelOptions"
                    style="width: 100%"
                    clearable
                />
              </n-form-item>
            </n-grid-item>
            <n-grid-item :span="6">
              <n-form-item label="Refiner" path="defaultVae">
                <n-select
                    :options="refinerOptions"
                    v-model:value="text2ImgPrompt.refiner_model_name"
                />
              </n-form-item>
            </n-grid-item>
            <n-grid-item :span="6">
              <n-form-item label="尺寸" path="aspect_ratios_selection">
                <n-select
                    :options="aspect_ratios"
                    v-model:value="text2ImgPrompt.aspect_ratios_selection"
                    label-field="size"
                    value-field="size"
                    :render-label="renderLabel"
                    clearable
                />
              </n-form-item>
            </n-grid-item>
          </n-grid>
        </n-form>
      </n-spin>
    </n-card>
    <n-grid :x-gap="5">
      <n-grid-item span="14">
        <n-card style="height: 460px;">
          <n-space justify="center">
            <n-el v-if="selectedPic != '' && selectedPic != null  "
                  style="background: var(--hover-color);margin-top:10px">
              <n-space style="padding: 10px;">
                <n-image
                    :height="300"
                    :src=fileFunction.getViewFilePathByUserFileId(selectedPic)
                />
              </n-space>
            </n-el>
          </n-space>
          <n-space style="margin-top:20px">
            <n-scrollbar x-scrollable style="max-height: 80px">
              <div style="white-space: nowrap;">
                <n-image v-for="pic in picList"
                         preview-disabled
                         :lazy="true"
                         :width="70"
                         size="small"
                         @click="selectedPic = pic"
                         :class="{ 'selected': pic == selectedPic }"
                         style="margin-left: 10px;"
                         :src=fileFunction.getViewFilePathByUserFileId(pic)
                />
              </div>
            </n-scrollbar>
          </n-space>
        </n-card>
        <n-card style="margin-top: 5px;">
          <n-form :label-width="100" :model="text2ImgPrompt" :rules="rules" ref="formRef2">
            <n-form-item-gi path="prompt" label="正向提示词">
              <n-input v-model:value="text2ImgPrompt.prompt" type="textarea" style="height: 80px"/>
              <n-button v-if="isResourceOk==true" type="primary" style="height: 80px;width: 80px;margin-left:5px;" @click="generateImg"
                        :loading="buttonLoading">
                生成
              </n-button>
            </n-form-item-gi>
          </n-form>
        </n-card>
      </n-grid-item>
      <n-grid-item span="10">
        <n-card>
          <n-form :model="text2ImgPrompt" :rules="rules" ref="formRef3">
            <n-grid :x-gap="5">
              <n-grid-item :span="15">
                <n-form-item label="出图模式" path="performance_selection">
                  <n-radio-group v-model:value="text2ImgPrompt.performance_selection" name="performance">
                    <n-space>
                      <n-radio value="Speed">
                        普通模式
                      </n-radio>
                      <n-radio value="Quality">
                        质量模式
                      </n-radio>
                      <n-radio value="Extreme Speed">
                        急速模式
                      </n-radio>
                    </n-space>
                  </n-radio-group>
                </n-form-item>
              </n-grid-item>
              <n-grid-item :span="9">
                <n-form-item label="种子(-1随机)" path="image_seed">
                  <n-input-group>
                    <n-input-number v-model:value="text2ImgPrompt.image_seed" :min=-1></n-input-number>
                  </n-input-group>
                </n-form-item>
              </n-grid-item>
            </n-grid>
            <n-grid :cols="24" :x-gap="5">
              <n-form-item-gi :span="8" label="生成数量" path="image_number">
                <n-input-number v-model:value="text2ImgPrompt.image_number" :max="4" :min="1">
                </n-input-number>
              </n-form-item-gi>
              <n-form-item-gi :span="8" label="Guidance Scale" path="guidance_scale">
                <n-input-number v-model:value="text2ImgPrompt.guidance_scale" :min="0" :max="30">
                </n-input-number>
              </n-form-item-gi>
              <n-form-item-gi :span="8" label="Sampling Sharpness" path="sharpness">
                <n-input-number v-model:value="text2ImgPrompt.sharpness" :min="0" :max="30">
                </n-input-number>
              </n-form-item-gi>
            </n-grid>
            <n-form-item path="negativePrompt" label="反向提示词" :show-label="false">
              <n-input v-model:value="text2ImgPrompt.negative_prompt" placeholder="输入反向提示词"/>
            </n-form-item>
            <n-tabs
                class="card-tabs"
                default-value="style"
                size="large"
                animated
                pane-wrapper-style="margin: 0 -4px"
                pane-style="padding-left: 4px; padding-right: 4px; box-sizing: border-box;"
            >
              <n-tab-pane name="style" tab="风格" display-directive="show">
                <n-scrollbar style="max-height: 400px">
                  <n-checkbox-group v-model:value="text2ImgPrompt.style_selections">
                    <n-grid :y-gap="8" :cols="3">
                      <n-gi v-for="style in stylesOption">
                        <n-checkbox :value="style.label" :label="style.translation"/>
                      </n-gi>
                    </n-grid>
                  </n-checkbox-group>
                </n-scrollbar>
              </n-tab-pane>
              <n-tab-pane name="lora" tab="Lora" display-directive="show">
                <n-grid :x-gap="6" v-for="(lora,index) in text2ImgPrompt.loras">
                  <n-grid-item :span="12">
                    <n-form-item-gi :label="`loRA ` + (index + 1)">
                      <n-select :options="loraOptions" v-model:value="lora.model_name" clearable>
                      </n-select>
                    </n-form-item-gi>
                  </n-grid-item>

                  <n-grid-item :span="12">
                    <n-form-item-gi label="权重">
                      <n-input-number :min="-2" :max="2" :step="0.01" v-model:value="lora.weight"></n-input-number>
                    </n-form-item-gi>
                  </n-grid-item>
                </n-grid>
              </n-tab-pane>
            </n-tabs>


          </n-form>
        </n-card>
      </n-grid-item>
    </n-grid>
  </div>
</template>

<script setup lang="ts">
import {onMounted, reactive, ref} from 'vue';
import {useMessage} from 'naive-ui';
// @ts-ignore
import fileFunction from '@/libs/globalFunction/file.js'
import {fooocusControllerApi} from "@/api/paint/fooocusController.api"
import {fooocusDict} from '@/dictionary/fooocusDict'
const {styleTranslation,aspect_ratios} = fooocusDict()
const isResourceOk = ref(true)

const checked = ref(false)
const formRef1 = ref(null)
const formRef2 = ref(null)
const formRef3 = ref(null)
const message = useMessage()
const resourceLoading = ref(false)
const modelOptions = ref([])
const refinerOptions = ref([])
const loraOptions = ref([])
const stylesOption = ref([])

const rules = {
  base_model_name: {
    required: true,
    message: '请选择模型'
  },
  aspect_ratios_selection: {
    required: true,
    message: '请选择尺寸'
  },
  performance_selection:{
    required: true,
    message: '请选择出图模式'
  },
  image_seed:{
    required: true,
    message: '请确认种子数'
  },
  image_number:{
    required: true,
    message: '请确认生成数量'
  },
  guidance_scale:{
    required: true,
    message: '请确认Guidance Scale'
  },
  sharpness:{
    required: true,
    message: '请确认Sampling Sharpness'
  },
};


// 加载配置
const loadConfig = (storyCreatorConfig: any, selectedResource: string) => {
  // 当前的资源是否为已选中的资源
  resourceSelect(selectedResource)
}

// 获取配置
const getConfig = async ()=>{
  return Promise.all([
    validateForm(formRef1),
    validateForm(formRef2),
    validateForm(formRef3)
  ]).then(async (results) => {
    const allValid = results.every((valid) => valid)
    if (allValid) {
      let copyText2ImgPrompt = {...text2ImgPrompt};
      copyText2ImgPrompt.loras = copyText2ImgPrompt.loras.filter(item => item.model_name !== "" && item.model_name != null )
      console.log(copyText2ImgPrompt)
      return copyText2ImgPrompt
    }else {
      return null
    }
  })
}

const resourceSelect = (resourceId: string) => {
  text2ImgPrompt.resourceId = resourceId
  getResourceConfig(resourceId)
}

// 获取SD资源详情
const getResourceConfig = (resouceId: string) => {
  resourceLoading.value = true
  fooocusControllerApi.getFooocusModelInfo(resouceId).then(res => {
    if (res.code === 200) {
      isResourceOk.value = true
      modelOptions.value = []
      res.data.model_filenames.forEach((item: any) => {
        // @ts-ignore
        modelOptions.value.push({
          label: item,
          value: item
        })
      })
      if (res.data.model_filenames.length > 0) {
        text2ImgPrompt.base_model_name = res.data.model_filenames[0]
      }
      refinerOptions.value = []
      res.data.refiner_filenames?.forEach((item: any) => {
        // @ts-ignore
        refinerOptions.value.push({
          label: item,
          value: item
        })
      })
      if (res.data.refiner_model_name?.length > 0) {
        text2ImgPrompt.refiner_model_name = res.data.refiner_model_name[0]
      }

      loraOptions.value = []
      res.data.lora_filenames?.forEach((item: any) => {
        // @ts-ignore
        loraOptions.value.push({
          label: item,
          value: item
        })
      })

      stylesOption.value = []
      res.data.styles?.forEach((item: any) => {
        // @ts-ignore
        const styleItem = {
          label: item,
          translation: item
        }
        styleTranslation.value.forEach((style: any) => {
          if (style.original === styleItem.label) {
            styleItem.translation = style.translation
          }
        })
        stylesOption.value.push(styleItem)
      })
    } else {
      isResourceOk.value = false
    }
  }).catch(()=>{
    isResourceOk.value = false
  }).finally(() => {
    resourceLoading.value = false
  })
}

// 初始化数据
const text2ImgPrompt: Fooocus.Text2ImgModel = reactive({
  resourceId: '',
  prompt: '',
  negative_prompt: '',
  style_selections: [
    "Fooocus V2",
    "Fooocus Enhance",
    "Fooocus Sharp"
  ],
  performance_selection: 'Extreme Speed',
  aspect_ratios_selection: '1152×896',
  image_number: 1,
  image_seed: -1,
  sharpness: 2,
  guidance_scale: 4,
  base_model_name: 'juggernautXL_version6Rundiffusion.safetensors',
  refiner_model_name: '',
  refiner_switch: 0.5,
  loras: [{
    model_name: "sd_xl_offset_example-lora_1.0.safetensors",
    weight: 0.1
  }, {
    model_name: "",
    weight: 1
  }, {
    model_name: "",
    weight: 1
  }, {
    model_name: "",
    weight: 1
  }],
  advanced_params: {
    disable_preview: false,
    adm_scaler_positive: 1.5,
    adm_scaler_negative: 0.8,
    adm_scaler_end: 0.3,
    refiner_swap_method: "joint",
    adaptive_cfg: 7,
    sampler_name: "dpmpp_2m_sde_gpu",
    scheduler_name: "karras",
    overwrite_step: -1,
    overwrite_switch: -1,
    overwrite_width: -1,
    overwrite_height: -1,
    overwrite_vary_strength: -1,
    overwrite_upscale_strength: -1,
    mixing_image_prompt_and_vary_upscale: false,
    mixing_image_prompt_and_inpaint: false,
    debugging_cn_preprocessor: false,
    skipping_cn_preprocessor: false,
    controlnet_softness: 0.25,
    canny_low_threshold: 64,
    canny_high_threshold: 128,
    freeu_enabled: false,
    freeu_b1: 1.01,
    freeu_b2: 1.02,
    freeu_s1: 0.99,
    freeu_s2: 0.95,
    debugging_inpaint_preprocessor: false,
    inpaint_disable_initial_latent: false,
    inpaint_engine: "v1",
    inpaint_strength: 1,
    inpaint_respective_field: 1
  },
  require_base64: true,
  async_process: false,
});


const drawerWidth = ref(0)

const picList = ref([])
const selectedPic = ref(null)
const buttonLoading = ref(false)

/**初始化事件**/
onMounted(() => {
  // 设置当前drawerWidth 宽度
  drawerWidth.value = window.innerWidth - 300;
  window.addEventListener('resize', handleResize);
})

// 窗口宽度变化
const handleResize = () => {
  drawerWidth.value = window.innerWidth - 300;
}

/**提交任务**/
const generateImg = async () => {
  Promise.all([
    validateForm(formRef1),
    validateForm(formRef2),
    validateForm(formRef3)
  ]).then(async (results) => {
    const allValid = results.every((valid) => valid)
    if (allValid) {
      buttonLoading.value = true;
      let copyText2ImgPrompt = {...text2ImgPrompt};
      copyText2ImgPrompt.loras = copyText2ImgPrompt.loras.filter(item => item.model_name !== "" && item.model_name != null )
      // 更新prompt
       await fooocusControllerApi.generateText2ImgAndCheck(copyText2ImgPrompt, 5 * 60 * 1000).then(res => {
         if (res) {
           const images = res.imageUrl.split(',')
           for (let i = 0; i < images.length; i++) {
             picList.value.push(images[i])
           }
           selectedPic.value = images[0]
         }
      }).finally(() => {
        buttonLoading.value = false;
      })
    }
  })

}



const validateForm = (fr:any) =>{
  return new Promise((resolve) => {
    fr.value?.validate((errors) => {
      if(!errors){
        resolve(true)
      }else {
        resolve(false)
      }
    });
  });
}


const renderLabel = (option: any) => {
  return option.size + ' 【比例:' + option.ratio + '】'
}



defineExpose({
  getConfig, loadConfig
})


</script>
<style>
.selected {
  border: 3px solid #8250df;
}
</style>
